#include "PenroseTiling.h"
#include <iostream>
#include <math.h>
#include <GL/glew.h>

#define PI 3.14159265

PenroseTiling::PenroseTiling(void)
{
	//generate fibonaci numbers
	FiboNumber[0] = 0.f;
	FiboNumber[1] = 1.f;
	for (int i = 2; i < __FIBONUM; i++)
		FiboNumber[i] = FiboNumber[i-1] + FiboNumber[i-2];
}

PenroseTiling::~PenroseTiling(void)
{
}


void PenroseTiling::Tiling(int w, int h, float ratio)
{
	//initialize 2 first tile e,f
	int maxnumtile = 5000000;
	int ns = 2.f;
	PTILE ps = new TILE[maxnumtile];

	float xl = -w/2.f-(h/2.f)*tan(54.f*PI/180.f);
	float xr = -xl;
	float yt = h/2.f + (w/2.f)*tan(36.f*PI/180.f);
	float yb = -yt;

	float area = yt*2.f*xr;
	int pointnum = area / ratio;

	ps[0].p0 = POINT2D(0.f, yt);
	ps[0].p1 = POINT2D(xr, 0.f);
	ps[0].p2 = POINT2D(xl, 0.f);
	ps[0].id = 0;
	ps[0].fiboId = 2;
	ps[0].tileType = 4;

	ps[1].p0 = POINT2D(0.f, yb);
	ps[1].p1 = POINT2D(xl, 0.f);
	ps[1].p2 = POINT2D(xr, 0.f);
	ps[1].id = 0;
	ps[1].fiboId = 2;
	ps[1].tileType = 5;

	int subdivlevel = 0;
	int count = 0;
	PTILE pd = new TILE[maxnumtile];
	while (subdivlevel < ratio) //(count < pointnum)
	{
		subdivlevel++;
		int nd = 0;
		for (int i = 0; i < ns; i++)
		{
			switch (ps[i].tileType)
			{
			case 0:			//tile a
				nd++;
				pd[nd-1] = ps[i]; pd[nd-1].tileType = 1;
				break;
			case 1:			//tile b
				nd++;
				pd[nd-1] = ps[i]; pd[nd-1].tileType = 0;
				break;
			case 2:			//tile c
				//f00*
				nd++;
				pd[nd-1].p0 = ps[i].p0 + (ps[i].p1 - ps[i].p0).normalize()*(ps[i].p1 - ps[i].p2).length();
				pd[nd-1].p1 = ps[i].p2;
				pd[nd-1].p2 = ps[i].p0;
				pd[nd-1].id = ps[i].id;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 5;
				//c10
				nd++;
				pd[nd-1].p0 = ps[i].p2;
				pd[nd-1].p1 = pd[nd-2].p0;
				pd[nd-1].p2 = ps[i].p1;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*0 + FiboNumber[ps[i].fiboId+1]*1;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 2;
				//a10
				nd++;
				pd[nd-1].p0 = pd[nd-3].p0;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*0 + FiboNumber[ps[i].fiboId+1]*1;
				pd[nd-1].tileType = 0;

				count++;
				break;
			case 3:			//tile d
				//e00
				nd++;
				pd[nd-1].p0 = ps[i].p0 + (ps[i].p2 - ps[i].p0).normalize()*(ps[i].p1 - ps[i].p2).length();
				pd[nd-1].p1 = ps[i].p0;
				pd[nd-1].p2 = ps[i].p1;
				pd[nd-1].id = ps[i].id;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 4;
				//d10
				nd++;
				pd[nd-1].p0 = ps[i].p1;
				pd[nd-1].p1 = ps[i].p2;
				pd[nd-1].p2 = pd[nd-2].p0;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*0 + FiboNumber[ps[i].fiboId+1]*1;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 3;
				break;
			case 4:			//tile e
				//f00
				nd++;
				pd[nd-1].p0 = ps[i].p2 + (ps[i].p0 - ps[i].p2).normalize()*(ps[i].p0 - ps[i].p1).length()*(0.5f/cos(36.f*PI/180.f));
				pd[nd-1].p1 = ps[i].p1 + (ps[i].p2 - ps[i].p1).normalize()*(ps[i].p0 - ps[i].p1).length()*(0.5f/cos(36.f*PI/180.f));
				pd[nd-1].p2 = ps[i].p2;
				pd[nd-1].id = ps[i].id;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 5;
				//c10
				nd++;
				pd[nd-1].p0 = pd[nd-2].p1;
				pd[nd-1].p1 = pd[nd-2].p0;
				pd[nd-1].p2 = ps[i].p0;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*0 + FiboNumber[ps[i].fiboId+1]*1;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 2;
				//e01
				nd++;
				pd[nd-1].p0 = pd[nd-3].p1;
				pd[nd-1].p1 = ps[i].p0;
				pd[nd-1].p2 = ps[i].p1;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*1 + FiboNumber[ps[i].fiboId+1]*0;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 4;
				//a10
				nd++;
				pd[nd-1].p0 = pd[nd-4].p0;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*0 + FiboNumber[ps[i].fiboId+1]*1;
				pd[nd-1].tileType = 0;

				count++;
				break;
			case 5:		//tile f
				//e00
				nd++;
				pd[nd-1].p0 = ps[i].p1 + (ps[i].p0 - ps[i].p1).normalize()*(ps[i].p0 - ps[i].p2).length()*(0.5f/cos(36.f*PI/180.f));
				pd[nd-1].p1 = ps[i].p1;
				pd[nd-1].p2 = ps[i].p2 + (ps[i].p1 - ps[i].p2).normalize()*(ps[i].p0 - ps[i].p2).length()*(0.5f/cos(36.f*PI/180.f));
				pd[nd-1].id = ps[i].id;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 4;
				//d10
				nd++;
				pd[nd-1].p0 = pd[nd-2].p2;
				pd[nd-1].p1 = ps[i].p0;
				pd[nd-1].p2 = pd[nd-2].p0;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*0 + FiboNumber[ps[i].fiboId+1]*1;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 3;
				//f01
				nd++;
				pd[nd-1].p0 = pd[nd-3].p2;
				pd[nd-1].p1 = ps[i].p2;
				pd[nd-1].p2 = ps[i].p0;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*1 + FiboNumber[ps[i].fiboId+1]*0;
				pd[nd-1].fiboId =ps[i].fiboId + 2;
				pd[nd-1].tileType = 5;
				//a01
				nd++;
				pd[nd-1].p0 = pd[nd-4].p2;
				pd[nd-1].id = ps[i].id + FiboNumber[ps[i].fiboId]*1 + FiboNumber[ps[i].fiboId+1]*0;
				pd[nd-1].tileType = 0;

				count++;
				break;
			}
		}
		ns = nd;
		PTILE tmp = ps;
		ps = pd;
		pd = tmp;
	}

	printf("number of sampling points: %d\n", count);
	float x,y;
	for (int i = 0; i < ns; i++)
	{
		if (ps[i].tileType == 0 || ps[i].tileType == 1)
		{
			x = ps[i].p0.x + w/2.f;
			y = ps[i].p0.y + h/2.f;
			if (x >=0 && x <= w && y >= 0 && y <= h)
				glVertex3f(x, y, ps[i].id*1.f/150000);
		}
	}

	delete[] ps;
	delete[] pd;
}